// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
function clamp(min, value, max) {
return Math.max(Math.min(value, max), min);
}
// Initialize OverlayScrollbars
document.addEventListener("DOMContentLoaded", () => {
let bodyScroller = window.OverlayScrollbars(document.body, {
callbacks: {
onScroll: function (ev) {
const scrollInfo = bodyScroller.scroll();
const scrollTop = ev.target.scrollTop;
const max = scrollInfo.max.y;
floatingNavBar(max, scrollTop);
}
}
});
});
// drop-in $.ajax replacement with identical lifecycle and cancellation behavior
// please don't use this for new code
function notAjax(options) {
const {
url,
type: method,
data,
beforeSend,
success,
error,
complete
} = options;
const params = data && Object.fromEntries([...Object.entries(data)].filter(([k, v]) => v != null));
const queryString = params && "?" + new URLSearchParams(params) || "";
const abortController = new AbortController();
(async () => {
beforeSend && beforeSend();
try {
const response = await fetch(url + queryString, {
method,
signal: abortController.signal
// `credentials: "include"` is intentionally omitted - without, cookies will only be sent to same origin
});
if (!response.ok) {
throw new Error((await response.text()) || "Kaputt!");
}
success && success(await response.text());
} catch (ex) {
error && error(ex);
} finally {
complete && complete();
}
})();
return abortController;
}
// Dropdowns
if (document.querySelector('.dropdown-btn')) {
const btns = document.querySelectorAll('.dropdown-btn');
const menus = document.querySelectorAll('.dropdown-menu');
btns.forEach(btn => {
btn.addEventListener('mousedown', e => {
e.preventDefault();
e.stopPropagation();
if (e.target.classList.contains('btn')) e.target.focus();
});
btn.addEventListener('click', e => {
if (e.target.classList.contains('select-input')) e.target.focus();
const openMenus = document.querySelectorAll('.dropdown-menu.open');
const menu = e.target.parentElement.querySelector('.dropdown-menu');
e.stopPropagation();
if (!menu.classList.contains('open')) {
openMenus.forEach(openMenu => {
openMenu.classList.remove('open');
});
}
btn.childNodes.forEach(node => {
node.addEventListener('click', e => e.stopPropagation());
});
if (menu.classList.contains('open')) {
menu.classList.add('closing');
setTimeout(() => {
menu.classList.remove('closing', 'open');
}, 150);
} else {
menu.classList.add('open');
}
});
});
window.addEventListener('keydown', e => {
if (e.key === 'Escape') {
e.stopPropagation();
menus.forEach(menu => {
if (menu.classList.contains('open')) {
menu.classList.add('closing');
setTimeout(() => {
menu.classList.remove('closing', 'open');
}, 150);
}
})
}
})
menus.forEach(menu => {
menu.addEventListener('click', e => e.stopPropagation());
menu.childNodes.forEach(node => {
node.addEventListener('click', e => e.stopPropagation());
});
menu.querySelectorAll('.menu-item').forEach(item => {
item.addEventListener('keydown', e => {
if (e.key === 'Enter' || e.key === ' ') item.click();
});
});
});
document.body.addEventListener("click", e => {
document.querySelectorAll('.dropdown-menu').forEach(menu => {
if (menu.classList.contains('open')) {
menu.classList.add('closing');
setTimeout(() => {
menu.classList.remove('closing', 'open');
}, 150);
}
});
});
}
// Modals
const modals = document.querySelectorAll('.modal-container');
function toggleModal(node) {
if (node) {
if (node.classList.contains('open')) {
node.classList.add('closing');
setTimeout(() => {
node.classList.remove('closing', 'open');
}, 150);
} else {
node.classList.add('open');
node.focus();
}
}
}
function disableModalButton(e) {
e.target.setAttribute('disabled', '');
e.target.innerHTML = `
`;
}
window.addEventListener('keydown', e => {
if (e.key === 'Escape') {
modals.forEach(modal => {
if (modal.classList.contains('open')) {
modal.classList.add('closing');
setTimeout(() => {
modal.classList.remove('closing', 'open');
}, 150);
}
});
}
});
// Checkboxes
const checkboxes = document.querySelectorAll('.checkbox');
checkboxes.forEach(item => {
item.addEventListener('keypress', e => {
if (e.key === 'Enter' || e.key === ' ') {
e.target.click();
}
});
});
// Searchbars
const searchbars = document.querySelectorAll('.search-container');
if (searchbars) {
searchbars.forEach(searchbar => {
const searchInput = searchbar.querySelector('input');
const clearBtn = searchbar.querySelector('.search-clear-btn');
searchInput.addEventListener('input', e => {
if (e.target.value) {
clearBtn.classList.add('visible');
} else {
clearBtn.classList.remove('visible');
}
});
clearBtn.addEventListener('click', e => {
searchInput.value = '';
clearBtn.classList.remove('visible');
});
});
}
// Quick downloader
window.addEventListener('keydown', e => {
if (!localStorage.getItem('quickSelectMode')) localStorage.setItem('quickSelectMode', 'download');
if ((e.ctrlKey && e.key === 'k') || e.ctrlKey && e.key === '/') {
e.preventDefault();
const modalContainerDOM = document.getElementById('quickselect-modal');
if (modalContainerDOM) {
toggleModal(modalContainerDOM);
if (modalContainerDOM.classList.contains('open')) modalContainerDOM.querySelector('.text-input').focus();
return;
} else {
const viewIcon = ``;
const downloadIcon = ``;
const modalContainer = Object.assign(document.createElement('div'), {
className: 'modal-container open',
id: 'quickselect-modal',
innerHTML : `
`
});
tippy.delegate('body', {
target: '.quickselect-mode-toggle',
hideOnClick: false,
offset: 0,
placement: 'left',
content: `Current Mode: ${localStorage.getItem('quickSelectMode')[0].toUpperCase() + localStorage.getItem('quickSelectMode').slice(1)}`,
theme: 'default'
});
modalContainer.querySelector('.quickselect-mode-toggle').addEventListener('click', e => {
const currentMode = localStorage.getItem('quickSelectMode');
if (currentMode === 'download') {
localStorage.setItem('quickSelectMode', 'view');
e.target.innerHTML = viewIcon;
e.target._tippy.setContent(`Current Mode: ${localStorage.getItem('quickSelectMode')[0].toUpperCase() + localStorage.getItem('quickSelectMode').slice(1)}`);
} else if (currentMode === 'view') {
localStorage.setItem('quickSelectMode', 'download');
e.target.innerHTML = downloadIcon;
e.target._tippy.setContent(`Current Mode: ${localStorage.getItem('quickSelectMode')[0].toUpperCase() + localStorage.getItem('quickSelectMode').slice(1)}`);
}
});
let selectedIndex = 0;
let setIndex = index => {
const visibleItems = modalContainer.querySelectorAll('li:not(.hidden)');
if (visibleItems.length) {
modalContainer.querySelectorAll('li.selected').forEach(item => {
item.classList.remove('selected');
});
selectedIndex = index;
visibleItems[selectedIndex].classList.add('selected');
visibleItems[selectedIndex].scrollIntoView({block: 'nearest'});
}
}
async function getItems() {
await fetch(`https://api.${window.location.host}/latest/store/addons`)
.then(result => result.json())
.then(result => {
result.forEach(addon => {
const item = Object.assign(document.createElement('li'), {
innerHTML: `${(addon.type === 'theme' ? `` : ``)}
${addon.name}`
});
item.setAttribute('data-author', addon.author);
item.setAttribute('data-tags', `[${addon.tags.toString().replace(/,/g, ', ')}]`);
item.addEventListener('click', e => {
if (localStorage.getItem('quickSelectMode') === 'download') {
window.location.href = `${window.location.origin}/download?id=${addon.id}`;
} else if (localStorage.getItem('quickSelectMode') === 'view') {
window.location.href = `${window.location.origin}/${addon.type}?id=${addon.id}`;
}
item.addEventListener('keypress', e => {
if (e.key === 'Enter' || e.key === ' ') {
e.target.click();
}
});
});
modalContainer.querySelector('.modal-content').appendChild(item);
});
setIndex(0);
});
}
getItems();
const searchInput = modalContainer.querySelector('.text-input');
let handleKeyboard = e => {
const visibleItems = modalContainer.querySelectorAll('li:not(.hidden)');
if (e.key === 'ArrowDown' && !(selectedIndex >= visibleItems.length - 1)) {
setIndex(selectedIndex + 1);
} else if (e.key === 'ArrowDown' && selectedIndex >= visibleItems.length - 1) {
setIndex(0);
} else if (e.key === 'ArrowUp' && !(selectedIndex === 0)) {
setIndex(selectedIndex - 1);
} else if (e.key === 'ArrowUp' && selectedIndex === 0) {
setIndex(visibleItems.length - 1);
}
if (e.key === 'Escape') {
toggleModal(document.getElementById('quickselect-modal'));
}
}
document.body.appendChild(modalContainer);
searchInput.focus();
searchInput.addEventListener('input', e => {
e.preventDefault();
const symbols = ['@', '#'];
modalContainer.querySelectorAll('li').forEach(item => {
if (!symbols.includes(e.target.value.charAt(0))) {
if (!item.innerText.toLowerCase().includes(e.target.value.toLowerCase())) {
item.classList.add('hidden');
} else if (item.classList.contains('hidden')) {
item.classList.remove('hidden');
}
} else if (e.target.value.startsWith('@')) {
if (!item.getAttribute('data-author').toLowerCase().includes(e.target.value.substring(1).toLowerCase())) {
item.classList.add('hidden');
} else if (item.classList.contains('hidden')) {
item.classList.remove('hidden');
}
} else if (e.target.value.startsWith('#')) {
/*let dataTags = item.getAttribute('data-tags').replaceAll(" ", "").split(',');
if (!dataTags.every(v => e.target.value.substring(1).toLowerCase().replaceAll(" ", "").split(',').includes(v))) {
item.classList.add('hidden');
} else if (item.classList.contains('hidden')) {
item.classList.remove('hidden');
}*/
if (!item.getAttribute('data-tags').includes(e.target.value.substring(1).toLowerCase())) {
item.classList.add('hidden');
} else if (item.classList.contains('hidden')) {
item.classList.remove('hidden');
}
}
if (symbols.includes(e.target.value)) {
item.classList.remove('hidden');
}
});
setIndex(0);
});
searchInput.addEventListener('keydown', e => {
if (e.key === 'Enter' && modalContainer.querySelectorAll('li.selected:not(.hidden)').length) {
modalContainer.querySelectorAll('li.selected:not(.hidden)')[0].click();
}
});
setIndex(0);
modalContainer.querySelector('.modal-backdrop').addEventListener('click', e => {
toggleModal(document.getElementById('quickselect-modal'));
});
modalContainer.addEventListener('keydown', handleKeyboard);
}
}
});
// DOM Rendering
const parseHTML = function (string) {
const template = document.createElement("div");
template.innerHTML = string;
template.style = "display: contents;";
return template;
}
const renderChildren = function (element, children) {
children = children.flat(10);
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (!child) continue;
if (typeof child === "string" && child.charAt(0) === "<") element.appendChild(parseHTML(child));
else element.append(child);
}
};
const createElement = function (type, props = {}, ...children) {
props = props || {};
let element;
if (typeof type === "function") {
element = type(Object.assign(props, {children: props.children || children}));
if (!(element instanceof Element) && element !== null) throw "Components must return an HTMLElement";
} else if (typeof type === "string") {
element = document.createElement(type);
if (children.length) renderChildren(element, children);
for (let prop in props) {
if (prop === "children") {
renderChildren(element, Array.isArray(props.children) ? props.children : [props.children]);
} else if (prop.indexOf("on") === 0) {
element[prop.toLowerCase()] = props[prop];
} else if (prop === "className") {
element.classList.add(...props[prop].split(" "));
} else if (prop in element) {
element[prop] = props[prop];
} else {
element.setAttribute(prop, props[prop]);
}
}
}
if (!element && element !== null) throw "Element could not be rendered!";
return element;
};
const h = createElement;
async function copyInnerText(target) {
var msg, toast;
try {
await navigator.clipboard.writeText((target.querySelector(".copy-me") || target).innerText);
msg = "Copied to clipboard";
} catch (err) {
msg = err.message;
}
target.appendChild(toast = Object.assign(document.createElement("div"), {
innerText: msg,
className: "copy-toast",
}));
setTimeout(() => toast.remove(), 1000);
}